/* cDrawBox.h
 * User-drawn widget.
 */
#ifndef __newmoon_cdrawbox_h
#define __newmoon_cdrawbox_h

class DrawBox;
#include <list>
#include <string>
#include <gtk/gtk.h>
#include "debugout.h"
#include "compat.h"
#include "mathx.h"
#include "uint.h"
#include "cImgBuf.h"

class DrawBox {
	public:
		typedef void(*MouseButtonCallbackPtr)(DrawBox*, GtkWidget*, GdkEventButton*, bool, void*);
		typedef void(*MouseMoveCallbackPtr)(DrawBox*, GtkWidget*, GdkEventMotion*, u32, u32, GdkModifierType, void*);
		typedef void(*MouseScrollCallbackPtr)(DrawBox*, GtkWidget*, GdkEventScroll*, void*);
		typedef void(*ConfigureCallbackPtr)(DrawBox*, GtkWidget*, GdkEventConfigure*, void*);
		typedef void(*ExposeCallbackPtr)(DrawBox*, GtkWidget*, GdkEventExpose*, void*);
		
		typedef struct {
			union {
				MouseButtonCallbackPtr MouseButton;
				MouseMoveCallbackPtr MouseMove;
				MouseScrollCallbackPtr MouseScroll;
				ConfigureCallbackPtr Configure;
				ExposeCallbackPtr Expose;
			};
			void *UserData;
		} Callback;
		
		DrawBox();
		DrawBox(u32 Width, u32 Height);
		~DrawBox();
		void InstallButtonCallback(MouseButtonCallbackPtr Func, void *UserData, bool First);
		void RemoveButtonCallback(MouseButtonCallbackPtr Func);
		void InstallMouseMoveCallback(MouseMoveCallbackPtr Func, void *UserData, bool First);
		void RemoveMouseMoveCallback(MouseMoveCallbackPtr Func);
		void InstallMouseScrollCallback(MouseScrollCallbackPtr Func, void *UserData, bool First);
		void RemoveMouseScrollCallback(MouseScrollCallbackPtr Func);
		void InstallConfigureCallback(ConfigureCallbackPtr Func, void *UserData, bool First);
		void RemoveConfigureCallback(ConfigureCallbackPtr Func);
		void InstallExposeCallback(ExposeCallbackPtr Func, void *UserData, bool First);
		void RemoveExposeCallback(ExposeCallbackPtr Func);

		GdkPixmap* GetBackBuf();
		GtkWidget* GetDrawingArea();
		u32 GetWidth();
		u32 GetHeight();
		void SetFGColour(u8 R, u8 G, u8 B);
		void DrawPixel(u32 X, u32 Y);
		void DrawPixel(u32 X, u32 Y, u8 R, u8 G, u8 B);
		void DrawRectangle(u32 X, u32 Y, u32 Width, u32 Height, bool Filled);
		void DrawLine(u32 X1, u32 Y1, u32 X2, u32 Y2);
		void DrawArc(u32 X, u32 Y, u32 W, u32 H, s32 Start, s32 End, bool Filled);
		void DrawText(u32 X, u32 Y, std::string Text);
		void BlitFrom(DrawBox *Src, u32 SX, u32 SY, u32 DX, u32 DY, u32 W, u32 H);
		void BlitFrom(ImgBuf *Src, u32 SX, u32 SY, u32 DX, u32 DY, u32 W, u32 H);
		void InvalidateRegion(u32 X, u32 Y, u32 Width, u32 Height);
		void InvalidateAll();
		bool Resize(u32 Width, u32 Height);
		
		std::list<Callback>MouseButtonCallback;
		std::list<Callback>MouseMoveCallback;
		std::list<Callback>MouseScrollCallback;
		std::list<Callback>ConfigureCallback;
		std::list<Callback>ExposeCallback;
	
	protected:
		static std::list<DrawBox*> Instances;
		GdkPixmap *BackBuf;
		GtkWidget *DrawingArea;
		u32 Width, Height;
		u8 FGRed, FGGreen, FGBlue;
		PangoLayout *PLayout;
	
	private:
		void _Create(u32 Width, u32 Height);
		friend DrawBox* LookupDrawBox(GtkWidget *DrawingArea);
		friend gboolean DrawBoxButtonPressEvent(GtkWidget *Widget, GdkEventButton *Event, gpointer Box);
		friend gboolean DrawBoxButtonReleaseEvent(GtkWidget *Widget, GdkEventButton *Event, gpointer Box);
		friend gboolean DrawBoxScrollEvent(GtkWidget *Widget, GdkEventScroll *Event, gpointer Box);
		friend gboolean DrawBoxMotionEvent(GtkWidget *Widget, GdkEventMotion *Event, gpointer Box);
		friend gboolean DrawBoxConfigureEvent(GtkWidget *Widget, GdkEventConfigure *Event, gpointer Box);
		friend gboolean DrawBoxExposeEvent(GtkWidget *Widget, GdkEventExpose *Event, gpointer Box);
};

DrawBox* LookupDrawBox(GtkWidget *DrawingArea);
gboolean DrawBoxButtonPressEvent(GtkWidget *Widget, GdkEventButton *Event, gpointer Box);
gboolean DrawBoxButtonReleaseEvent(GtkWidget *Widget, GdkEventButton *Event, gpointer Box);
gboolean DrawBoxScrollEvent(GtkWidget *Widget, GdkEventScroll *Event, gpointer Box);
gboolean DrawBoxMotionEvent(GtkWidget *Widget, GdkEventMotion *Event, gpointer Box);
gboolean DrawBoxConfigureEvent(GtkWidget *Widget, GdkEventConfigure *Event, gpointer Box);
gboolean DrawBoxExposeEvent(GtkWidget *Widget, GdkEventExpose *Event, gpointer Box);
#endif //__newmoon_cdrawbox_h
